import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:developer';
import 'dart:ffi';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';

import 'package:android_intent_plus/android_intent.dart';
import 'package:elevator/get/intl_keys.dart';
import 'package:elevator/model/alerm_info.dart';
import 'package:elevator/model/lift_info.dart';
import 'package:elevator/model/notification_info.dart';
import 'package:elevator/model/user.dart';
import 'package:elevator/mqtt/mqtt_call_back.dart';
import 'package:elevator/mqtt/mqtt_manager.dart';
import 'package:elevator/utils/eventbus.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_app_badger/flutter_app_badger.dart';
import 'package:get/get.dart';
import 'package:mqtt_client/mqtt_client.dart';
import 'package:mysql1/mysql1.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:typed_data/typed_data.dart';

import '../../global.dart';
import '../../model/build_info.dart';
import '../../mqtt/constant.dart';
import '../../utils/mynotification.dart';
import '../../utils/utils_dialog.dart';
import '../../utils/utils_logger.dart';
import 'package:mysql1/mysql1.dart' as mysql;

class PageHomeLogic extends GetxController {

  var time;
  var currentIndex = 0;
  PageController? pageController;
  late User user;

  PageHomeLogic() {
    pageController = PageController(initialPage: currentIndex);
    // checkServer();
  }

  jumpTo(int index) => pageController!.jumpToPage(index);

  ///退出逻辑处理，两秒内不退出应用
  Future<bool> willPop() async {
    if (time == null ||
        DateTime.now().difference(time) > const Duration(seconds: 2)) {
      time = DateTime.now();
      snack(IntlKeys.moreClickToExit.tr);
      return false;
    }
    logd(
        "time $time \ncurrent :${DateTime.now()} \n${DateTime.now().difference(time)}",
        target: "page_home");
    if (Platform.isAndroid) {
      const intent = AndroidIntent(
          action: "android.intent.action.MAIN",
          flags: [0x10000000],
          category: "android.intent.category.HOME");
      intent.launch();
      return false;
    }

    return true;
  }

  @override
  void onReady() {
    super.onReady();
    User user = Get.arguments;
    logPrint("user:" + user.toString());
    setUser(user);
    loadInfo();
  }

  @override
  void onClose() {
    // TODO: implement onClose
    super.onClose();
  }

  void setUser(User u) {
    user = u;
  }

  void loadInfo(){
    if(null!=user && null!=user.psBuilds && user.psBuilds != ""){
      List<String>? buildIds = user.psBuilds?.split("/");
      getBuildIdInfo(buildIds!);
    }
  }
  ///电梯信息 <key：buildId，value:电梯信息>
  Map<String,BuildInfo> buildInfoMap = HashMap();

  /// 查询出用户所有的buildid对应的配置信息,加载完成后启动mqtt连接，连接成功后开启订阅
  ///
  void getBuildIdInfo(List<String> buildIds) async {
    await Future.forEach(buildIds,(buildId) async{
      queryBuildIdInfo(buildId).then((buildInfo) => {
          buildInfoMap[buildId] = buildInfo,
          bus.emit(bus.buildInfoKey, buildInfo),
          print("建筑：$buildId 加载完成，$buildInfoMap")
      },onError: (e){
        logPrint(e);
      });
    }).whenComplete(() => {
      logPrint("开始初始化mqtt"),
      initState(),
      startConnectMqtt(),
      logPrint("mqtt初始化完成")
    });
  }

  Future queryBuildIdInfo(String buildId) async {
    logPrint("start queryUserInfo");
    var settings = mysql.ConnectionSettings(
        host: '36.141.45.30',
        port: 43306,
        user: 'root',
        password: 'adminemqx123',
        db: 'liftDB_$buildId',
        useCompression: false,
        timeout:const Duration(seconds: 60),
        maxPacketSize:16 * 1024 * 1024 *1024,
        characterSet: CharacterSet.UTF8MB4);
    var conn = await mysql.MySqlConnection.connect(settings);

    var liftList = await conn
        .query('select * from tbAppLiftCfg');
    var cfgInfoList = await conn
        .query('select * from tbAppCfgInfo');
    BuildInfo buildInfo = BuildInfo();
    buildInfo.buildId = buildId;
    //buildInfo.load(liftList,cfgInfoList);
    await conn.close();
    return Future.value(buildInfo);
  }

  late MQTTManager mqttManager;
  void startConnectMqtt(){
    if(null!=user && null!=user.psBuilds && user.psBuilds != ""){
      List<String> builds = [];
      if(user.psBuilds!.contains("/")){
        builds.addAll(user.psBuilds!.split("/"));
      }else{
        builds.add(user.psBuilds!);
      }
      mqttManager = MQTTManager();
      mqttManager.clentId = user.psName!;
      mqttManager.callBack = MqttCallBack(onConnected, onDisconnected, onSubscribed
          , onSubscribeFail, onUnsubscribed, onMessaged,pong);
      mqttManager.connect();
    }
  }


  // 连接成功
  void onConnected() {
    MQTTManager mqttManager = MQTTManager();
    if(null!=user && null!=user.psBuilds && user.psBuilds != ""){
        List<String>? builds = user.psBuilds?.split("/");
          for(String buildId in builds!){
            mqttManager.subscribe(Constant.TOPIC_QUERY_SVP + buildId, MqttQos.atLeastOnce);
            mqttManager.subscribe(Constant.TOPIC_QUERY_TPC + buildId, MqttQos.atLeastOnce);
          }
    }
  }

  void onMessaged(String topic,Uint8Buffer byteBuffer){
    if(null!=topic && topic.isNotEmpty){
      if(topic.startsWith(Constant.TOPIC_QUERY_SVP)){
        parseSvp(topic,byteBuffer);
      }else if(topic.startsWith(Constant.TOPIC_QUERY_TPC)){
        parseTpc(topic,byteBuffer);
      }
    }
  }

  void parseSvp(String topic,Uint8Buffer byteBuffer){
    int buildIdIndex = topic.lastIndexOf("/");
    String buildId = topic.substring(buildIdIndex+1);
    List<int> byteList = byteBuffer.toList();
    if(byteList.length>8 && byteList.first == 0xA5 && byteList.last == 0x17){
      BuildInfo buildInfo;
      if(buildInfoMap.containsKey(buildId)){
        buildInfo = buildInfoMap[buildId]!;
      }else{
        return;
      }
      buildInfo.buildId = buildId;
      logPrint("收到电梯"+topic+"状态信息-------------");
      int index = 1;
      int length = byteList.elementAt(index);
      index++;
      int type = byteList.elementAt(index);
      index++;
      int com = byteList.elementAt(index);
      index++;
      int num = byteList.elementAt(index);
      logPrint("电梯"+topic+"总长："+byteList.length.toString()+",包长："+length.toString()+",num:"+num.toString());

      for(int i=0;i<num;i++){
        int order = (com - 1) * 6 + i + 1;
        index++;
        int switchState = byteList.elementAt(index);
        index++;
        int currentState = byteList.elementAt(index);
        index++;
        int currentAddr = byteList.elementAt(index);
        index++;
        int data = byteList.elementAt(index) * 100;
        index++;
        data = data + byteList.elementAt(index) * 10;
        index++;
        data = data + byteList.elementAt(index);
        index++;
        int alerm1 = byteList.elementAt(index);
        index++;
        int alerm2 = byteList.elementAt(index);
        index++;
        int alerm3 = byteList.elementAt(index);
        index++;
        int alerm4 = byteList.elementAt(index);

        if(buildInfo.liftInfoStateMaps.containsKey(order)){
          LiftInfo liftInfo = buildInfo.liftInfoStateMaps[order]!;
          if(null != liftInfo.liftName && liftInfo.liftName.isNotEmpty){
            logPrint("svp:read to update----------------");
            liftInfo.currentAddr = buildInfo.getLiftAddr(currentAddr);
            liftInfo.currentState = buildInfo.getLiftState(currentState);
            liftInfo.alermList = buildInfo.getSpvAlermInfo(liftInfo,alerm1,alerm2,alerm3,alerm4);
            alermCheck(200,buildId,liftInfo);
            liftInfo.updateState();
            buildInfo.liftInfoStateMaps[order] = liftInfo;
            logPrint("svp:UPDATE:$liftInfo ++++++++++++");
          }
        }else{
          LiftInfo liftInfo = LiftInfo();
          liftInfo.order = order;
          if(null != liftInfo.liftName && liftInfo.liftName.isNotEmpty){
            logPrint("svp:read to add------------------");
            liftInfo.currentAddr = buildInfo.getLiftAddr(currentAddr);
            liftInfo.currentState = buildInfo.getLiftState(currentState);
            liftInfo.alermList = buildInfo.getSpvAlermInfo(liftInfo,alerm1,alerm2,alerm3,alerm4);
            alermCheck(200,buildId,liftInfo);
            buildInfo.liftInfoStateMaps[order] = liftInfo;
            logPrint("svp:ADD:$liftInfo ++++++++++++++++");
          }
        }
      }
      buildInfoMap[buildId] = buildInfo;
      bus.emit(bus.buildInfoKey, buildInfo);
      logPrint("SVP:"+topic+"："+buildInfo.toString());
    }else{
      logPrint("电梯"+buildId+"状态信息解析错误-------------");
    }
  }

  void parseTpc(String topic,Uint8Buffer byteBuffer){
    int buildIdIndex = topic.lastIndexOf("/");
    String buildId = topic.substring(buildIdIndex+1);

    if(byteBuffer.length==230 && byteBuffer.first == 0xA5 && byteBuffer.last == 0x17){
      BuildInfo buildInfo;
      if(buildInfoMap.containsKey(buildId)){
        buildInfo = buildInfoMap[buildId]!;
      }else{
        return;
      }
      logPrint("收到电梯"+topic+"状态信息-------------");
      int index = 1;
      int length = byteBuffer.elementAt(index);
      index++;
      int type = byteBuffer.elementAt(index);
      index++;
      int currentAddr = byteBuffer.elementAt(index);
      index++;
      Iterable<int> dayList = byteBuffer.getRange(index, index+128);
      String day = String.fromCharCodes(dayList);
      index+=128;
      Iterable<int> versionList= byteBuffer.getRange(index, index+32);
      String version = String.fromCharCodes(versionList);
      index+=32;

      Iterable<int> elevatoDataList= byteBuffer.getRange(index, index+63);
      int elevatoIndex = 0;
      int ep = elevatoDataList.elementAt(elevatoIndex);
      bool showEp = false;
      if(ep==0x86){
        showEp = true;
      }
      bool showPus = false;
      bool showPuw = false;
      elevatoIndex+=2;
      int pus1 = elevatoDataList.elementAt(elevatoIndex);
      elevatoIndex++;
      int pus2 = elevatoDataList.elementAt(elevatoIndex);
      elevatoIndex+=2;
      elevatoIndex++;
      int puw1 = elevatoDataList.elementAt(elevatoIndex);
      elevatoIndex++;
      int puw2 = elevatoDataList.elementAt(elevatoIndex);
      elevatoIndex++;

      index+=63;

      if(buildInfo.liftInfoStateMaps.containsKey(currentAddr)){
        LiftInfo liftInfo = buildInfo.liftInfoStateMaps[currentAddr]!;
        liftInfo.order = currentAddr;
        liftInfo.day = day;
        liftInfo.version = version;
        buildInfo.loadAlermInfo(liftInfo);
        alermCheck(100,buildId,liftInfo);
        liftInfo.updateState();
        buildInfo.liftInfoStateMaps[currentAddr] = liftInfo;
        buildInfo.buildId = buildId;
        buildInfoMap[buildId] = buildInfo;
      }else{
        LiftInfo liftInfo = LiftInfo();
        liftInfo.order = currentAddr;
        if(null != liftInfo.liftName && liftInfo.liftName.isNotEmpty){
          liftInfo.day = day;
          liftInfo.version = version;

          buildInfo.loadAlermInfo(liftInfo);
          alermCheck(100,buildId,liftInfo);
          buildInfo.liftInfoStateMaps[currentAddr] = liftInfo;
          buildInfo.buildId = buildId;
          buildInfoMap[buildId] = buildInfo;
        }
      }
      logPrint("TPC:"+topic+"："+buildInfo.toString());
    }else{
      logPrint("电梯"+buildId+"状态信息解析错误-------------");
    }
  }

  ///APP进入后台监听器
  late final AppLifecycleListener _listener;
  late AppLifecycleState? _state;
  bool appShow = true;

  ///每隔30秒检测一次电梯列表状态定时器
  late Timer periodicTimer;

  void initState() {
    _state = SchedulerBinding.instance.lifecycleState;
    _listener = AppLifecycleListener(
      onShow: () => _handleTransition('show'),
      onResume: () => _handleTransition('resume'),
      onHide: () => _handleTransition('hide'),
      onInactive: () => _handleTransition('inactive'),
      onPause: () => _handleTransition('pause'),
      onDetach: () => _handleTransition('detach'),
      onRestart: () => _handleTransition('restart'),
    );

    periodicTimer = Timer.periodic(
      const Duration(seconds: 30),//每隔30秒检测一次电梯列表状态
          (timer) {
        DateTime now = DateTime.now();
        logPrint("AAAA 检测电梯状态"+now.toString());
        if(null != buildInfoMap && buildInfoMap.isNotEmpty){
          for(BuildInfo buildInfo in buildInfoMap.values){
            if(null != buildInfo.liftInfoStateMaps && buildInfo.liftInfoStateMaps.isNotEmpty){
              for(LiftInfo liftInfo in buildInfo.liftInfoStateMaps.values){
                liftInfo.checkClearState(now);
              }
            }
          }
        }
      },
    );
  }

  void _handleTransition(String state) {
    if(identical("show",state)){
      appShow = true;
      clearAlermNotification();
    }else if(identical("hide",state)){
      appShow = false;
    }
    logPrint("########################## main $state");
    appShow = false;
  }

  Map<String,NotificationInfo> alermNotifMaps = {};
  int alermNotifCount = 0;

  /// 检查警告信息是否需要发送通知栏
  void alermCheck(int type,String buildId,LiftInfo liftInfo){
    if(null!=liftInfo){
      if(null!=liftInfo.alermList && liftInfo.alermList.isNotEmpty){
        for(AlermInfo alermInfo in liftInfo.alermList){
          NotificationInfo notificationInfo = NotificationInfo(buildId, alermInfo.number, alermInfo.getTag(), alermInfo.type, liftInfo.liftName, liftInfo.order,"");
          String key = notificationInfo.getKey();
          if( !alermNotifMaps.keys.contains(key)){
            alermNotifMaps[key] = notificationInfo;
            showNotification(type, notificationInfo);
          }
        }
      }else{
        String liftKey = NotificationInfo.getLiftKey(buildId,liftInfo.liftName, liftInfo.order);
        alermNotifMaps.removeWhere((key, value) => key.startsWith(liftKey));
      }
    }
  }

  Future<void> showNotification(int type, NotificationInfo notificationInfo) async {
    if(!appShow){
      alermNotifCount ++;
      if ( await FlutterAppBadger.isAppBadgeSupported()) {
        FlutterAppBadger.updateBadgeCount(alermNotifCount);
      }
      if (Platform.isAndroid) {
        if ( await Permission.notification.request().isGranted) {
          sendNotification(type, notificationInfo);
        }else{
          logPrint("isGranted false");
          //打开应用设置
          final flag = await UtilsDialog.showSingleNoticeDialog(Get.context!, IntlKeys.openSetting.tr);
          if(flag != null && flag){
            openAppSettings();
          }
        }
      } else {
        sendNotification(type, notificationInfo);
      }

    }
  }

  void sendNotification(int type, NotificationInfo notificationInfo) {
    logPrint("isGranted true");
    //点击发送通知
    Map params = {};
    params['type'] = type;
    params['content'] = "content";
    int rid = int.parse(_randomBit(9));
    notification.send(IntlKeys.warning.tr, notificationInfo.getContent(),notificationId: rid, params: notificationInfo.toString());
  }

  void clearAlermNotification() {
    alermNotifCount = 0;
    FlutterAppBadger.removeBadge();
  }

  // 连接断开
  void onDisconnected() {

  }

  // 订阅主题成功
  void onSubscribed(String topic) {

  }

  // 订阅主题失败
  void onSubscribeFail(String topic) {

  }

  // 成功取消订阅
  void onUnsubscribed(String? topic) {

  }

  // 收到 PING 响应
  void pong() {

  }

  _randomBit(int len) {
    String scopeF = '123456789'; //首位
    String scopeC = '0123456789'; //中间
    String result = '';
    for (int i = 0; i < len; i++) {
      if (i == 0) {
        result = scopeF[Random().nextInt(scopeF.length)];
      } else {
        result = result + scopeC[Random().nextInt(scopeC.length)];
      }
    }  return result;
  }

  logPrint(String msg) {
    if (false) {
      debugPrint(msg);
    }
  }

}
